package com.zzy.aop.version2;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 灵光一现，简化模拟AOP的实现（猜的，主要训练编程思维，回顾和运用所学知识）
 */
public class AOP {

    /**
     * 此方法模拟一个切面方法
     */
    public static <T> void aopOperation(String classPath,T obj) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
        //根据类路径生成类对象
        Class classObj = Class.forName(classPath);

        //根据类对象获取所有方法对象
        Method[] methods = classObj.getDeclaredMethods();

        //判断类上是否存在AOPAnno注解标识
        Annotation classAOPAnno = classObj.getAnnotation(AOPAnno.class);

        if (classAOPAnno != null){
            //类上存在AOPAnno注解标识，将类中所有方法加入切面编程

            //遍历methods
            for (Method method : methods) {
//                System.out.println("AOP 前置业务代码");
//                //对方法进行爆破，取消访问检查
//                method.setAccessible(true);
//                //这里进行简化，假设所有方法签名均为无参
//                method.invoke(obj);
//                System.out.println("AOP 后置业务代码");
                aopMethod(method,obj);
            }
            return;
        }

        //类上不存在AOPAnno注解标识，判断类中方法上否存在AOPAnno注解标识
        for (Method method : methods) {
            AOPAnno methodAOPAnno = method.getAnnotation(AOPAnno.class);
            if (methodAOPAnno != null){
//                //该方法上存在AOPAnno注解标识，则加入切面编程
//                System.out.println("AOP 前置业务代码");
//                //对方法进行爆破，取消访问检查
//                method.setAccessible(true);
//                //这里进行简化，假设所有方法签名均为无参
//                method.invoke(obj);
//                System.out.println("AOP 后置业务代码");
                aopMethod(method,obj);
            }
        }
    }

    private static  <T> void aopMethod(Method method, T obj) throws InvocationTargetException, IllegalAccessException {
        System.out.println("AOP 前置业务代码");
        //对方法进行爆破，取消访问检查
        method.setAccessible(true);
        //这里进行简化，假设所有方法签名均为无参 无返回值
        method.invoke(obj);
        System.out.println("AOP 后置业务代码");
    }
}
